#include <iostream>
#include <string>
#include <list>
#include <set>


using namespace std;
using uint = unsigned int;

class PhscialHost;

//虚拟节点
class VirtualHost
{
public:
    VirtualHost(string ip,PhscialHost* pthscicalHost)
                :ip(ip)
                ,pthscialHost(pthscicalHost)
    {
        //md5 = 通过md5算法计算得来
    }
    bool operator<(const VirtualHost& host) const
    {
        return md5 < host.md5;
    }
    bool operator==(const VirtualHost& host) const
    {
        return ip == host.ip;
    }
    uint getMd5() const
    {
        return md5;
    }
    PhscialHost* getpthscialHost() const
    {
        return pthscialHost;
    }
private:
    string ip;  //虚拟节点ip地址
    uint md5;   //虚拟节点在环上的md5值
    PhscialHost* pthscialHost;   //虚拟节点指向的物理节点
};

//物理节点
class PhscialHost
{
public:
    PhscialHost(string ip,int virNum):ip(ip)
    {
        for(int i = 0;i < virNum;i++) {
            virtualHost.emplace_back(
                ip+"#"+to_string(i),this
            );
        }
    }
    const string getIp() const
    {
        return ip;
    }
    const list<VirtualHost>& getVirtualHosts() const
    {
        return virtualHost;
    }
private:
    string ip;  //物理节点地址
    list<VirtualHost> virtualHost;  //虚拟节点列表。
};

//一致性哈希
class ConsistenHash
{
public:
    //在一致性哈希环上增加物理主机的虚拟节点
    void addVirtaulHost(PhscialHost& pthscialHost)
    {
        //获取物理主机的所有虚拟节点
        auto list = pthscialHost.getVirtualHosts();
        //将所有虚拟节点都插入到一致性哈希环上
        for(auto host : list) {
            virtaulHosts_.emplace(host);
        }
    }
    //在一致性哈希环上删除物理主机的虚拟节点
    void deleteVirtaulHost(PhscialHost& pthscialHost)
    {
        //获取物理主机的所有虚拟节点
        auto list = pthscialHost.getVirtualHosts();
        //将所有虚拟节点都从一致性哈希环上删除
        for(auto host : list) {
            auto it = virtaulHosts_.find(host);
            if(it != virtaulHosts_.end()) {
                virtaulHosts_.erase(it);
            }
        }

    }
    //返回负载的实际物理节点
    string getPhscialHost(string clientIp) const
    {
        //uint md5 = md5(clientIp);
        for(auto host : virtaulHosts_) {
            // if(host.getMd5() > md5) {
            //     //最终获取到这个，就算一致性哈希彻底完成任务
            //     return host.getpthscialHost()->getIp();
            // }
        }
    }
private:
    set<VirtualHost> virtaulHosts_;     //一致性哈希环。
};
